#ifndef TESTSHH
#define TESTSHH
#include "errors.hh"
#include "stdincludes.hh"
#include "typedefs.hh"
#include <iostream>

namespace licada
{
    class TestFailException : std::exception
    {
	std::string reason;
    public:
	TestFailException( int line, const char* file ) {
	    using namespace std;

	    ostringstream writer;
	    writer << "Test failed at line: " << line << " in file: " << file << endl;
	    reason = writer.str().c_str();
	}
	virtual ~TestFailException() throw() {}
	const std::string& getReason() const { return reason; }
    };

#define TEST_TRUE( x ) { if (!(x)) throw licada::TestFailException( __LINE__, __FILE__ ); }
#define TEST_FALSE( x ) { if ((x)) throw licada::TestFailException( __LINE__, __FILE__ ); }
#define TEST_EQ( x, y ) { if ( (x) != (y) ) throw licada::TestFailException( __LINE__, __FILE__ ); }
#define TEST_NEQ( x, y ) { if ( (x) == (y) ) throw licada::TestFailException( __LINE__, __FILE__ ); }

    class TestBase
    {
    public:
	virtual ~TestBase() {}
	virtual TNameType getName() { return ""; }
	virtual void setup() {}
	virtual void testPrecondition() {}
	virtual void doOperation() {}
	virtual void testPostcondition() {}
	virtual void teardown(){}
	
	virtual void run() {
	    setup();
	    try
	    {
		testPrecondition();
		doOperation();
		testPostcondition();
		teardown();
	    }
	    catch( ... )
	    {
		teardown();
		throw;
	    }
	}
    };
    
    template<typename TestType>
    void runTest()
    {
	using namespace std;
	TestType test;
	TNameType name = test.getName();
	if ( name && *name )
	    cout << "Running test: " << name << endl;
	else
	    cout << "Running unnamed test" << endl;
	try
	{
	    test.run();
	}
	catch( licada::TestFailException& exc )
	{
	    cout << exc.getReason().c_str() << endl;
	}
	catch( licada::LicadaError& exc )
	{
	    cout << "Error at frame: " << endl << exc.getStackTrace();
	}
	catch( std::exception& exc )
	{
	    cout << "Unknown exception during test" << endl;
	}
	catch( ... )
	{
	    cout << "Unknown object thrown during test" << endl;
	}
    }


}
#endif
